package org.mybatis.generator.plugins;

import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.config.PropertyRegistry;
import org.mybatis.generator.internal.util.StringUtility;

import java.util.ArrayList;
import java.util.List;

/**
 * 生成 自定义 dao 类
 *  配置示例：
 <plugin type="org.mybatis.generator.plugins.MyDaoPlugin">
     <property name="targetPackage" value="com.cu.haigou.account.dao"/>
     <property name="implementationPackage" value="com.cu.haigou.account.dao.impl"/>
     <property name="targetProject" value="src/test/out"/>
     <property name="iDao" value="com.cu.woego.base.dao.IDao"/>
     <property name="baseDao" value="com.cu.woego.base.dao.BaseDao"/>
     <property name="enableAnnotation" value="true"/>
 </plugin>
 *
 * @author zhiji.mo
 * @date 2014-12-6 上午10:34:45
 */
public class MyDaoPlugin extends PluginAdapter {


    private FullyQualifiedJavaType interfaceImplType;
    private FullyQualifiedJavaType daoType;
    private FullyQualifiedJavaType interfaceType;
    private FullyQualifiedJavaType pojoType;
    private FullyQualifiedJavaType repository;
    private FullyQualifiedJavaType iDaoType;
    private FullyQualifiedJavaType baseDaoType;

    private String myDaoPack;
    private String myDaoImplPack;
    private String project;
    private String pojoUrl;
    private String iDao;
    private String baseDao;

    private List<Method> methods;
    /**
     * 是否添加注解
     */
    private boolean enableAnnotation = true;


    public MyDaoPlugin() {
        super();
        methods = new ArrayList<Method>();
    }

    public boolean validate(List<String> warnings) {
        if (StringUtility.stringHasValue(properties.getProperty("enableAnnotation")))
            enableAnnotation = StringUtility.isTrue(properties.getProperty("enableAnnotation"));

        myDaoPack = properties.getProperty("targetPackage");
        myDaoImplPack = properties.getProperty("implementationPackage");
        project = properties.getProperty("targetProject");
        pojoUrl = context.getJavaModelGeneratorConfiguration().getTargetPackage();
        iDao = properties.getProperty("iDao");
        baseDao = properties.getProperty("baseDao");

        if (enableAnnotation) {
            repository = new FullyQualifiedJavaType("org.springframework.stereotype.Repository");
        }
        return true;
    }

    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
        List<GeneratedJavaFile> files = new ArrayList<GeneratedJavaFile>();
        String table = introspectedTable.getBaseRecordType();
        String tableName = table.replaceAll(this.pojoUrl + ".", "");

        interfaceType = new FullyQualifiedJavaType(myDaoPack + "." + tableName + "Dao");
        daoType = new FullyQualifiedJavaType(introspectedTable.getMyBatis3JavaMapperType());
        interfaceImplType = new FullyQualifiedJavaType(myDaoImplPack + "." + tableName + "DaoImpl");
        pojoType = new FullyQualifiedJavaType(pojoUrl + "." + tableName);
        iDaoType = new FullyQualifiedJavaType(iDao);
        baseDaoType = new FullyQualifiedJavaType(baseDao);

        iDaoType.addTypeArgument(introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType());
        iDaoType.addTypeArgument(pojoType);

        baseDaoType.addTypeArgument(introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType());
        baseDaoType.addTypeArgument(pojoType);


        Interface interface1 = new Interface(interfaceType);
        interface1.addSuperInterface(iDaoType);

        TopLevelClass topLevelClass = new TopLevelClass(interfaceImplType);
        topLevelClass.setSuperClass(baseDaoType);

        // 导入必要的类
        addImport(interface1, topLevelClass);

        // 接口
        addMethod(interface1, introspectedTable, tableName, files);
        // 实现类
        addMethodImpl(topLevelClass, introspectedTable, tableName, files);

        return files;
    }

    /**
     * 添加接口
     *
     * @param tableName
     * @param files
     */
    protected void addMethod(Interface interface1, IntrospectedTable introspectedTable, String tableName, List<GeneratedJavaFile> files) {
        interface1.setVisibility(JavaVisibility.PUBLIC);
        GeneratedJavaFile file = new GeneratedJavaFile(interface1, project,
                context.getProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING),
                context.getJavaFormatter());
        files.add(file);
    }

    /**
     * 添加实现类
     *
     * @param introspectedTable
     * @param tableName
     * @param files
     */
    protected void addMethodImpl(TopLevelClass topLevelClass, IntrospectedTable introspectedTable, String tableName, List<GeneratedJavaFile> files) {
        topLevelClass.setVisibility(JavaVisibility.PUBLIC);
        // 设置实现的接口
        topLevelClass.addSuperInterface(interfaceType);
        topLevelClass.addMethod(getMapperNameSpace(introspectedTable, tableName));
        if (enableAnnotation) {
            topLevelClass.addAnnotation("@Repository");
            topLevelClass.addImportedType(repository);
        }
        // 生成文件
        GeneratedJavaFile file = new GeneratedJavaFile(topLevelClass, project,
                context.getProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING),
                context.getJavaFormatter());
        files.add(file);
    }


    /**
     * 添加 getMapperNameSpace 方法
     */
    protected Method getMapperNameSpace(IntrospectedTable introspectedTable, String tableName) {
        Method method = new Method();
        method.setName("getMapperNameSpace");
        method.setReturnType(new FullyQualifiedJavaType("java.lang.String"));
        method.setVisibility(JavaVisibility.PUBLIC);
        StringBuilder sb = new StringBuilder();
        method.addBodyLine("return " + daoType.getShortName() + ".class.getName();");
        return method;
    }

    /**
     * 导入需要的类
     */
    private void addImport(Interface interfaces, TopLevelClass topLevelClass) {
        interfaces.addImportedType(pojoType);
        interfaces.addImportedType(iDaoType);
        topLevelClass.addImportedType(daoType);
        topLevelClass.addImportedType(interfaceType);
        topLevelClass.addImportedType(pojoType);
        topLevelClass.addImportedType(baseDaoType);
        if (enableAnnotation) {
            topLevelClass.addImportedType(repository);
        }
    }


}
